ItIron2022
Javascript
在進入之後的微型專案之前,我們先來個陣列練習吧! 陣列在幾乎所有的專案中都有著一席之地,其中很多常見的操作都可以透過es6之後的一些語法簡單的達成,今天讓我們扮演著面對不講理客戶的工程師,一一解決他對一些陣列操作的要求吧!
今天我們預計完成以下幾個陣列的操作
陣列的複製
先從基本一點的東西開始吧,今天客戶給你了以下的陣列,同時千交代萬交代你在做後續的操作時不要影響到原本的陣列,否則要給你好看! 為了不激怒客戶,我們只好想各種辦法來進行陣列的複製。
// 以下為原始陣列
const arr = ['Danny', 'Mike', 'John', 'John', 'Tao', 'John', 'Mike']
// 請建立一個result陣列,有著與arr陣列完全相同的值與排序
// your code here
這算是實務上很常見的情境,有非常多種方法足夠讓你切入這個問題,我們先來張防雷圖讓你思考一下,等等就簡單帶過幾個常見方法。
我不能說你錯,這確實是一種可行的方法,先宣告一個空陣列接著利用迴圈一個一個推進該陣列中,可以!
const result = [];
for (let i = 0; i < arr.length; i++) {
result.push(arr[i]);
}
另一種方法是利用Array.slice方法,直接從頭切到尾,最終會產生一個複製後的陣列
const result = arr.slice();
當slice方法不傳遞任何參數進去時便會預設從頭切到尾,也就是整個陣列的值。
接下來這個可說是我最常用的方法了,es6新增的擴展運算子無論在陣列或物件上都有相當廣的應用範圍,其中複製值的部分非常實用
const result = [...arr];
以上提供了三種可能的複製陣列方法,而手段遠遠不止這一些,不過只要有這些武器應該夠你用了!
值得注意的是這些方法全部都是所謂的淺拷貝,深淺拷貝的差異請參考我去年的文章,剛好是該篇的主題。
陣列的排序
現在複製完畢了,客戶要求我們對這個新的result陣列進行排序,他希望讓這個陣列按照英文字母序排序(sort alphabetically)! 你也許會想說,簡單! javascript陣列本來就有個sort方法嘛! 而且照預設,sort的排序會將陣列內的元素轉為字串後對照unicode並按照對應的值進行排序,也就剛好符合字母排序的要求,這樣寫應該就行了吧!
const sortedResult = result.sort()
正當你洋洋得意時,客戶轉頭過來跟你說『啊!抱歉,要排序的是這個陣列才對,那就麻煩你囉!』
const newArr = [{name: 'Danny'}, {name: 'Mike'}, {name: 'John'}, {name: 'John'},{name: 'Tao'}, {name: 'John'}, {name: 'Mike'}]
你忍著想灌他一拳的念頭開始思考,好在sort是可以傳入所謂的comparison function,也就是一個函數讓sort知道你想怎麼樣去做排序,比方說今天你想從小排到大,那麼最常見的寫法便是
const demo = [10, 1, 2]
console.log(demo.sort((a, b) => a - b)) // [1, 2, 10]
上述程式碼會有效是因為它會以裡面的comparison function回傳的結果作為如何排序的標準,一次會比較兩個數字a & b,而根據回傳的值會有以下的操作
理解這一點之後,要完成客戶的要求也就不是這麼困難囉! 跟範例唯一的差別在於字串不能用"-"運算符去做運算產生回傳值,因此我們需要麻煩一點,三個case都要手動處理到。
const newArr = [{name: 'Danny'}, {name: 'Mike'}, {name: 'John'}, {name: 'John'},{name: 'Tao'}, {name: 'John'}, {name: 'Mike'}]
newArr.sort((a, b) => {
// 若a.name在排序上大於b.name,將a往後移
if (a.name > b.name) {
return 1
// 若a.name在排序上小於b.name,將a往前移
} else if (a.name < b.name) {
return -1
}
// 除此之外的case,回傳0維持原排序
return 0
})
陣列的連接
解決完這個問題後,客戶馬上有了新的要求,說是現在突然拿到一份新的名單,要你將這兩份名單連接在一起組成新的陣列給他,新的資料要在舊的資料後,於是你又繼續埋頭苦幹了。
const oldList = ['Danny', 'Mike', 'John', 'John', 'Tao', 'John', 'Mike']
const newList = ['Mary', 'Mike', 'Joyce', 'Joyce', 'Mary']
好在這次的要求相當簡單,我們同樣有很多方法可以使用
一樣我們可以宣告一個新的陣列,而這個新陣列會是oldList的複製品,接著我們在用迴圈跑newList陣列一個一個元素推進去就行囉!
const result = [...oldList]
for (let i = 0; i < newList.length; i++) {
result.push(newList[i])
}
另一個選擇則是陣列原生的方法concat,也可以輕鬆地將兩個陣列連接在一起。
const result = [...oldList].concat(newList)
是的,看到前面的複製時我想你應該心裡有底了,實際上用擴展運算子複製兩個陣列再連接就行囉!
const result = [...oldList, ...newList]
統計陣列內出現的元素次數
終於到了今天最後一個要求了,在剛剛的陣列連接完成後,客戶又要一個新的資料,他希望你能替他統計陣列中每個名字出現的次數,最終以物件的方式展示結果。
const list = ['Danny', 'Mike', 'John', 'John', 'Tao', 'John', 'Mike', 'Mary', 'Mike', 'Joyce', 'Joyce', 'Mary']
這個需求就讓你有點傷腦筋了,你當然可以用迴圈配合預先建立一個空物件,然後檢查該名字是否已經在物件中,若有的話則令次數加1,沒有的話則將該名字加入物件並令次數為1,不過你現在趕著下班,希望可以用一串程式碼就直接搞定,因此你想到了es6的新語法reduce!
const countResult = list.reduce((obj,item)=>{
if (item in obj) {
obj[item]++
} else {
obj[item] = 1
}
return obj
},{})
最終的輸出結果也與你想的相同! 於是你就高高興興的下班了! 留下一臉矇逼的客戶與讀者
不過別擔心,這個統計的方法可以參照這篇文章,有非常詳細的說明
我們今天稍微休息了一下! 講了幾個陣列在實務上都很常見的應用方法,同時簡單的帶過reduce這個你可能有些陌生的語法,希望經過這幾個練習有讓你對於陣列的操作更上手一些,明天開始又會繼續新的微型專案開發囉! 接著,馬上進入我們今天的轉職Q & A環節吧!
Danny, 我目前已經開始在某某bootcamp開始上課,不過我總是很擔心自己學的不夠多,你有推薦什麼網路資源讓我能做額外的練習嗎?
很好的問題,網路上的免費/付費資源確實相當的多,完全到了令人眼花撩亂的地步,一開始會有些難以下手是很正常的,一般來說我會推薦幾個免費網站讓初學者去做練習.
通常我最先推薦的一定是這個免費課程,一共有30個小型專案,影片時間都不算太長,許多專案也做起來相當有趣,也是我這次鐵人賽主題選擇的靈感。
一個新手/高手都能把玩刷題網站,比起leetcode,在題目上更加有趣一些,可以藉由解題的過程增加你對於js的熟練度.
超級知名的教學網站,在youtube上也有非常多他們頻道的教學影片,每個你想學的主題都會有大量的練習可以做.
一般來說初學階段這樣就夠了,如果你想要更有系統性一點的話,可以在youtube上搜尋javascript tutorial之類的關鍵字,或是直接在特價時去udemy買個課程來上,真的不用怕沒有東西可以學,程式的水極深! 唯一我的建議會是,永遠都不要只看影片或文字教學,拜託拜託你一定要動手實作,不然你永遠都脫離不了所謂的教學影片地獄(tutorial hell),看再多教學都比不上你實際動手寫幾行code。
本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!